<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Detection of ArUco Boards</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d3/d81/tutorial_contrib_root.html">Tutorials for contrib modules</a></li><li class="navelem"><a class="el" href="../../d9/d6d/tutorial_table_of_content_aruco.html">ArUco marker detection (aruco module)</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Detection of ArUco Boards </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>An ArUco Board is a set of markers that acts like a single marker in the sense that it provides a single pose for the camera.</p>
<p>The most popular board is the one with all the markers in the same plane, since it can be easily printed:</p>
<div class="image">
<img src="../../gboriginal.png" alt="gboriginal.png"/>
</div>
<p>However, boards are not limited to this arrangement and can represent any 2d or 3d layout.</p>
<p>The difference between a Board and a set of independent markers is that the relative position between the markers in the Board is known a priori. This allows that the corners of all the markers can be used for estimating the pose of the camera respect to the whole Board.</p>
<p>When you use a set of independent markers, you can estimate the pose for each marker individually, since you dont know the relative position of the markers in the environment.</p>
<p>The main benefits of using Boards are:</p>
<ul>
<li>The pose estimation is much more versatile. Only some markers are necessary to perform pose estimation. Thus, the pose can be calculated even in the presence of occlusions or partial views.</li>
<li>The obtained pose is usually more accurate since a higher amount of point correspondences (marker corners) are employed.</li>
</ul>
<p>The aruco module allows the use of Boards. The main class is the <code><a class="el" href="../../d4/db2/classcv_1_1aruco_1_1Board.html" title="Board of markers. ">cv::aruco::Board</a></code> class which defines the Board layout:</p>
<div class="fragment"><div class="line"><span class="keyword">class  </span>Board {</div><div class="line"><span class="keyword">public</span>:</div><div class="line">    std::vector&lt;std::vector&lt;cv::Point3f&gt; &gt; objPoints;</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;cv::aruco::Dictionary&gt;</a> dictionary;</div><div class="line">    std::vector&lt;int&gt; ids;</div><div class="line">};</div></div><!-- fragment --><p>A object of type <code>Board</code> has three parameters:</p><ul>
<li>The <code>objPoints</code> structure is the list of corner positions in the 3d Board reference system, i.e. its layout. For each marker, its four corners are stored in the standard order, i.e. in clockwise order and starting with the top left corner.</li>
<li>The <code>dictionary</code> parameter indicates to which marker dictionary the Board markers belong to.</li>
<li>Finally, the <code>ids</code> structure indicates the identifiers of each of the markers in <code>objPoints</code> respect to the specified <code>dictionary</code>.</li>
</ul>
<h2>Board Detection </h2>
<p>A Board detection is similar to the standard marker detection. The only difference is in the pose estimation step. In fact, to use marker boards, a standard marker detection should be done before estimating the Board pose.</p>
<p>The aruco module provides a specific function, <code><a class="el" href="../../d9/d6a/group__aruco.html#ga366993d29fdddd995fba8c2e6ca811ea" title="Pose estimation for a board of markers. ">estimatePoseBoard()</a></code>, to perform pose estimation for boards:</p>
<div class="fragment"><div class="line"><a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a> inputImage;</div><div class="line"><span class="comment">// camera parameters are read from somewhere</span></div><div class="line"><a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a> cameraMatrix, distCoeffs;</div><div class="line">readCameraParameters(cameraMatrix, distCoeffs);</div><div class="line"><span class="comment">// assume we have a function to create the board object</span></div><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;cv::aruco::Board&gt;</a> board = <a class="code" href="../../d4/db2/classcv_1_1aruco_1_1Board.html#a06243c9dcd6fedf32992388aa7527f59">cv::aruco::Board::create</a>();</div><div class="line">...</div><div class="line">std::vector&lt;<span class="keywordtype">int</span>&gt; markerIds;</div><div class="line">std::vector&lt;std::vector&lt;cv::Point2f&gt;&gt; markerCorners;</div><div class="line"><a class="code" href="../../d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa">cv::aruco::detectMarkers</a>(inputImage, board.dictionary, markerCorners, markerIds);</div><div class="line"><span class="comment">// if at least one marker detected</span></div><div class="line"><span class="keywordflow">if</span>(markerIds.size() &gt; 0) {</div><div class="line">    <a class="code" href="../../d6/dcf/classcv_1_1Vec.html">cv::Vec3d</a> rvec, tvec;</div><div class="line">    <span class="keywordtype">int</span> valid = <a class="code" href="../../d9/d6a/group__aruco.html#ga366993d29fdddd995fba8c2e6ca811ea">cv::aruco::estimatePoseBoard</a>(markerCorners, markerIds, board, cameraMatrix, distCoeffs, rvec, tvec);</div><div class="line">}</div></div><!-- fragment --><p>The parameters of estimatePoseBoard are:</p>
<ul>
<li><code>markerCorners</code> and <code>markerIds</code>: structures of detected markers from <code><a class="el" href="../../d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa" title="Basic marker detection. ">detectMarkers()</a></code> function.</li>
<li><code>board</code>: the <code>Board</code> object that defines the board layout and its ids</li>
<li><code>cameraMatrix</code> and <code>distCoeffs</code>: camera calibration parameters necessary for pose estimation.</li>
<li><code>rvec</code> and <code>tvec</code>: estimated pose of the Board. If not empty then treated as initial guess.</li>
<li>The function returns the total number of markers employed for estimating the board pose. Note that not all the markers provided in <code>markerCorners</code> and <code>markerIds</code> should be used, since only the markers whose ids are listed in the <code>Board::ids</code> structure are considered.</li>
</ul>
<p>The <code><a class="el" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2" title="Draw coordinate system axis from pose estimation. ">drawAxis()</a></code> function can be used to check the obtained pose. For instance:</p>
<div class="image">
<img src="../../gbmarkersaxis.png" alt="gbmarkersaxis.png"/>
<div class="caption">
Board with axis</div></div>
<p> And this is another example with the board partially occluded:</p>
<div class="image">
<img src="../../gbocclusion.png" alt="gbocclusion.png"/>
<div class="caption">
Board with occlusions</div></div>
<p> As it can be observed, although some markers have not been detected, the Board pose can still be estimated from the rest of markers.</p>
<h2>Grid Board </h2>
<p>Creating the <code>Board</code> object requires specifying the corner positions for each marker in the environment. However, in many cases, the board will be just a set of markers in the same plane and in a grid layout, so it can be easily printed and used.</p>
<p>Fortunately, the aruco module provides the basic functionality to create and print these types of markers easily.</p>
<p>The <code>GridBoard</code> class is a specialized class that inherits from the <code>Board</code> class and which represents a Board with all the markers in the same plane and in a grid layout, as in the following image:</p>
<div class="image">
<img src="../../gboriginal.png" alt="gboriginal.png"/>
<div class="caption">
Image with aruco board</div></div>
<p> Concretely, the coordinate system in a Grid Board is positioned in the board plane, centered in the bottom left corner of the board and with the Z pointing out, like in the following image (X:red, Y:green, Z:blue):</p>
<div class="image">
<img src="../../gbaxis.png" alt="gbaxis.png"/>
<div class="caption">
Board with axis</div></div>
<p> A <code>GridBoard</code> object can be defined using the following parameters:</p>
<ul>
<li>Number of markers in the X direction.</li>
<li>Number of markers in the Y direction.</li>
<li>Length of the marker side.</li>
<li>Length of the marker separation.</li>
<li>The dictionary of the markers.</li>
<li>Ids of all the markers (X*Y markers).</li>
</ul>
<p>This object can be easily created from these parameters using the <code><a class="el" href="../../de/d05/classcv_1_1aruco_1_1GridBoard.html#a8f4db0a7faad559753887e9fdd43b74c" title="Create a GridBoard object. ">cv::aruco::GridBoard::create()</a></code> static function:</p>
<div class="fragment"><div class="line"><a class="code" href="../../de/d05/classcv_1_1aruco_1_1GridBoard.html">cv::aruco::GridBoard</a> board = <a class="code" href="../../de/d05/classcv_1_1aruco_1_1GridBoard.html#a8f4db0a7faad559753887e9fdd43b74c">cv::aruco::GridBoard::create</a>(5, 7, 0.04, 0.01, dictionary);</div></div><!-- fragment --><ul>
<li>The first and second parameters are the number of markers in the X and Y direction respectively.</li>
<li>The third and fourth parameters are the marker length and the marker separation respectively. They can be provided in any unit, having in mind that the estimated pose for this board will be measured in the same units (in general, meters are used).</li>
<li>Finally, the dictionary of the markers is provided.</li>
</ul>
<p>So, this board will be composed by 5x7=35 markers. The ids of each of the markers are assigned, by default, in ascending order starting on 0, so they will be 0, 1, 2, ..., 34. This can be easily customized by accessing to the ids vector through <code>board.ids</code>, like in the <code>Board</code> parent class.</p>
<p>After creating a Grid Board, we probably want to print it and use it. A function to generate the image of a <code>GridBoard</code> is provided in <code><a class="el" href="../../de/d05/classcv_1_1aruco_1_1GridBoard.html#aae344f00868cd472c430303c3cbfa998" title="Draw a GridBoard. ">cv::aruco::GridBoard::draw()</a></code>. For example:</p>
<div class="fragment"><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;cv::aruco::GridBoard&gt;</a> board = <a class="code" href="../../de/d05/classcv_1_1aruco_1_1GridBoard.html#a8f4db0a7faad559753887e9fdd43b74c">cv::aruco::GridBoard::create</a>(5, 7, 0.04, 0.01, dictionary);</div><div class="line"><a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a> boardImage;</div><div class="line">board-&gt;draw( <a class="code" href="../../d6/d50/classcv_1_1Size__.html">cv::Size</a>(600, 500), boardImage, 10, 1 );</div></div><!-- fragment --><ul>
<li>The first parameter is the size of the output image in pixels. In this case 600x500 pixels. If this is not proportional to the board dimensions, it will be centered on the image.</li>
<li><code>boardImage</code>: the output image with the board.</li>
<li>The third parameter is the (optional) margin in pixels, so none of the markers are touching the image border. In this case the margin is 10.</li>
<li>Finally, the size of the marker border, similarly to <code><a class="el" href="../../d6/d6e/group__imgproc__draw.html#ga644c4a170d4799a56b29f864ce984b7e" title="Draws a marker on a predefined position in an image. ">drawMarker()</a></code> function. The default value is 1.</li>
</ul>
<p>The output image will be something like this:</p>
<div class="image">
<img src="../../board.jpg" alt="board.jpg"/>
</div>
<p>A full working example of board creation is included in the <code>create_board.cpp</code> inside the module samples folder.</p>
<p>Note: The samples now take input via commandline via the <a href="http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0">OpenCV Commandline Parser</a>. For this file the example parameters will look like </p><div class="fragment"><div class="line"><span class="stringliteral">&quot;_output path_/aboard.png&quot;</span> -w=5 -h=7 -l=100 -s=10 -d=10</div></div><!-- fragment --><p>Finally, a full example of board detection:</p>
<div class="fragment"><div class="line"><a class="code" href="../../d8/dfe/classcv_1_1VideoCapture.html">cv::VideoCapture</a> inputVideo;</div><div class="line">inputVideo.<a class="code" href="../../d8/dfe/classcv_1_1VideoCapture.html#a614a1702e15f42ede5100014ce7f48ed">open</a>(0);</div><div class="line"></div><div class="line"><a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a> cameraMatrix, distCoeffs;</div><div class="line"><span class="comment">// camera parameters are read from somewhere</span></div><div class="line">readCameraParameters(cameraMatrix, distCoeffs);</div><div class="line"></div><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;cv::aruco::Dictionary&gt;</a> dictionary = <a class="code" href="../../d9/d6a/group__aruco.html#gaf5d7e909fe8ff2ad2108e354669ecd17">cv::aruco::getPredefinedDictionary</a>(<a class="code" href="../../d9/d6a/group__aruco.html#ggac84398a9ed9dd01306592dd616c2c975a6eb1a3e9c94c7123d8b1904a57193f16">cv::aruco::DICT_6X6_250</a>);</div><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;cv::aruco::GridBoard&gt;</a> board = <a class="code" href="../../de/d05/classcv_1_1aruco_1_1GridBoard.html#a8f4db0a7faad559753887e9fdd43b74c">cv::aruco::GridBoard::create</a>(5, 7, 0.04, 0.01, dictionary);</div><div class="line"></div><div class="line"><span class="keywordflow">while</span> (inputVideo.<a class="code" href="../../d8/dfe/classcv_1_1VideoCapture.html#ae38c2a053d39d6b20c9c649e08ff0146">grab</a>()) {</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a> image, imageCopy;</div><div class="line">    inputVideo.<a class="code" href="../../d8/dfe/classcv_1_1VideoCapture.html#a9ac7f4b1cdfe624663478568486e6712">retrieve</a>(image);</div><div class="line">    image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(imageCopy);</div><div class="line"></div><div class="line">    std::vector&lt;int&gt; ids;</div><div class="line">    std::vector&lt;std::vector&lt;cv::Point2f&gt; &gt; corners;</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa">cv::aruco::detectMarkers</a>(image, dictionary, corners, ids);</div><div class="line"></div><div class="line">    <span class="comment">// if at least one marker detected</span></div><div class="line">    <span class="keywordflow">if</span> (ids.size() &gt; 0) {</div><div class="line">        <a class="code" href="../../d9/d6a/group__aruco.html#ga2ad34b0f277edebb6a132d3069ed2909">cv::aruco::drawDetectedMarkers</a>(imageCopy, corners, ids);</div><div class="line"></div><div class="line">        <a class="code" href="../../d6/dcf/classcv_1_1Vec.html">cv::Vec3d</a> rvec, tvec;</div><div class="line">        <span class="keywordtype">int</span> valid = <a class="code" href="../../d9/d6a/group__aruco.html#ga366993d29fdddd995fba8c2e6ca811ea">estimatePoseBoard</a>(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec);</div><div class="line"></div><div class="line">        <span class="comment">// if at least one board marker detected</span></div><div class="line">        <span class="keywordflow">if</span>(valid &gt; 0)</div><div class="line">            <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">cv::aruco::drawAxis</a>(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1);</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">cv::imshow</a>(<span class="stringliteral">&quot;out&quot;</span>, imageCopy);</div><div class="line">    <span class="keywordtype">char</span> key = (char) <a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv::waitKey</a>(waitTime);</div><div class="line">    <span class="keywordflow">if</span> (key == 27)</div><div class="line">        <span class="keywordflow">break</span>;</div><div class="line">}</div></div><!-- fragment --><p>Sample video:</p>
<p> 
<iframe width="420" height="315" src="https://www.youtube.com/embed/Q1HlJEjW_j0" frameborder="0" allowfullscreen></iframe>
</p>
<p>A full working example is included in the <code>detect_board.cpp</code> inside the module samples folder.</p>
<p>Note: The samples now take input via commandline via the <a href="http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0">OpenCV Commandline Parser</a>. For this file the example parameters will look like </p><div class="fragment"><div class="line">-c=<span class="stringliteral">&quot;_path_&quot;</span>/calib.txt<span class="stringliteral">&quot; &quot;</span>_path_/aboard.png<span class="stringliteral">&quot; -w=5 -h=7 -l=100 -s=10 -d=10</span></div></div><!-- fragment --><h2>Refine marker detection </h2>
<p>ArUco boards can also be used to improve the detection of markers. If we have detected a subset of the markers that belongs to the board, we can use these markers and the board layout information to try to find the markers that have not been previously detected.</p>
<p>This can be done using the <code><a class="el" href="../../d9/d6a/group__aruco.html#ga13a2742381c0a48e146d230a8cda2e66" title="Refind not detected markers based on the already detected and the board layout. ">refineDetectedMarkers()</a></code> function, which should be called after calling <code><a class="el" href="../../d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa" title="Basic marker detection. ">detectMarkers()</a></code>.</p>
<p>The main parameters of this function are the original image where markers were detected, the Board object, the detected marker corners, the detected marker ids and the rejected marker corners.</p>
<p>The rejected corners can be obtained from the <code><a class="el" href="../../d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa" title="Basic marker detection. ">detectMarkers()</a></code> function and are also known as marker candidates. This candidates are square shapes that have been found in the original image but have failed to pass the identification step (i.e. their inner codification presents too many errors) and thus they have not been recognized as markers.</p>
<p>However, these candidates are sometimes actual markers that have not been correctly identified due to high noise in the image, very low resolution or other related problems that affect to the binary code extraction. The <code><a class="el" href="../../d9/d6a/group__aruco.html#ga13a2742381c0a48e146d230a8cda2e66" title="Refind not detected markers based on the already detected and the board layout. ">refineDetectedMarkers()</a></code> function finds correspondences between these candidates and the missing markers of the board. This search is based on two parameters:</p>
<ul>
<li>Distance between the candidate and the projection of the missing marker. To obtain these projections, it is necessary to have detected at least one marker of the board. The projections are obtained using the camera parameters (camera matrix and distortion coefficients) if they are provided. If not, the projections are obtained from local homography and only planar board are allowed (i.e. the Z coordinate of all the marker corners should be the same). The <code>minRepDistance</code> parameter in <code><a class="el" href="../../d9/d6a/group__aruco.html#ga13a2742381c0a48e146d230a8cda2e66" title="Refind not detected markers based on the already detected and the board layout. ">refineDetectedMarkers()</a></code> determines the minimum euclidean distance between the candidate corners and the projected marker corners (default value 10).</li>
<li>Binary codification. If a candidate surpasses the minimum distance condition, its internal bits are analyzed again to determine if it is actually the projected marker or not. However, in this case, the condition is not so strong and the number of allowed erroneous bits can be higher. This is indicated in the <code>errorCorrectionRate</code> parameter (default value 3.0). If a negative value is provided, the internal bits are not analyzed at all and only the corner distances are evaluated.</li>
</ul>
<p>This is an example of using the <code><a class="el" href="../../d9/d6a/group__aruco.html#ga13a2742381c0a48e146d230a8cda2e66" title="Refind not detected markers based on the already detected and the board layout. ">refineDetectedMarkers()</a></code> function:</p>
<div class="fragment"><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;cv::aruco::Dictionary&gt;</a> dictionary = <a class="code" href="../../d9/d6a/group__aruco.html#gaf5d7e909fe8ff2ad2108e354669ecd17">cv::aruco::getPredefinedDictionary</a>(<a class="code" href="../../d9/d6a/group__aruco.html#ggac84398a9ed9dd01306592dd616c2c975a6eb1a3e9c94c7123d8b1904a57193f16">cv::aruco::DICT_6X6_250</a>);</div><div class="line"><a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">cv::Ptr&lt;cv::aruco::GridBoard&gt;</a> board = <a class="code" href="../../de/d05/classcv_1_1aruco_1_1GridBoard.html#a8f4db0a7faad559753887e9fdd43b74c">cv::aruco::GridBoard::create</a>(5, 7, 0.04, 0.01, dictionary);</div><div class="line">std::vector&lt;int&gt; markerIds;</div><div class="line">std::vector&lt;std::vector&lt;cv::Point2f&gt;&gt; markerCorners, rejectedCandidates;</div><div class="line"><a class="code" href="../../d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa">cv::aruco::detectMarkers</a>(inputImage, dictionary, markerCorners, markerIds, <a class="code" href="../../d1/dcd/structcv_1_1aruco_1_1DetectorParameters.html">cv::aruco::DetectorParameters</a>(), rejectedCandidates);</div><div class="line"></div><div class="line">cv::aruco::refineDetectedMarkersinputImage, board, markerCorners, markerIds, rejectedCandidates);</div><div class="line"><span class="comment">// After calling this function, if any new marker has been detected it will be removed from rejectedCandidates and included</span></div><div class="line"><span class="comment">// at the end of markerCorners and markerIds</span></div></div><!-- fragment --><p>It must also be noted that, in some cases, if the number of detected markers in the first place is too low (for instance only 1 or 2 markers), the projections of the missing markers can be of bad quality, producing erroneous correspondences.</p>
<p>See module samples for a more detailed implementation. </p>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:38 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
